﻿using System;
using System.IO;
using System.Linq;
using System.Text;

namespace Fwql.Net.Extensions
{
    public static class ByteExtension
    {
        /// <summary>
        /// 转16进制
        /// </summary>
        /// <param name="b"></param>
        /// <returns></returns>
        public static string ToHex(this byte b)
        {
            return b.ToString("X2");
        }

        /// <summary>
        /// 转16进制
        /// </summary>
        /// <param name="bytes"></param>
        /// <param name="separator">分隔符</param>
        /// <returns></returns>
        public static string ToHex(this byte[] bytes, string separator = null)
        {
            return string.Join(separator, bytes.Select(b => b.ToString("X2")).ToList());
        }

        /// <summary>
        /// 转BASE64
        /// </summary>
        /// <param name="bytes"></param>
        /// <returns></returns>
        public static string ToBase64String(this byte[] bytes)
        {
            return Convert.ToBase64String(bytes);
        }

        /// <summary>
        /// 转原始字符串
        /// </summary>
        /// <param name="data"></param>
        /// <param name="encoding">编码方式</param>
        /// <returns></returns>
        public static string ToOriginString(this byte[] data, Encoding encoding = null)
        {
            encoding = encoding ?? Encoding.Default;
            return encoding.GetString(data);
        }

        /// <summary>
        /// 保存为文件
        /// </summary>
        /// <param name="data"></param>
        /// <param name="path">文件保存路径(全路径)</param>
        public static void SaveToFile(this byte[] data, string path)
        {
            File.WriteAllBytes(path, data);
        }

        /// <summary>
        /// 转内存流
        /// </summary>
        /// <param name="data"></param>
        /// <param name="writable">内存流是否可写</param>
        /// <returns></returns>
        public static MemoryStream ToMemoryStream(this byte[] data, bool writable = false)
        {
            return new MemoryStream(data, writable);
        }

        /// <summary>
        /// 转内存流
        /// </summary>
        /// <param name="data"></param>
        /// <param name="index">起始位置</param>
        /// <param name="count">长度</param>
        /// <param name="writable">内存流是否可写</param>
        /// <param name="publiclyVisible">true启用GetBuffer()</param>
        /// <returns></returns>
        public static MemoryStream ToMemoryStream(this byte[] data, int index, int count, bool writable = false,
                                                  bool publiclyVisible = false)
        {
            return new MemoryStream(data, index, count, writable, publiclyVisible);
        }

        /// <summary>
        /// 取得一个byte[]在另一个byte[]中第一次出现的位置
        /// </summary>
        /// <param name = "source">被检索的byte[]</param>
        /// <param name = "lookFor">检索项byte[]</param>
        /// <returns>第一次匹配的位置，-1表示未存在匹配位置</returns>
        public static int FirstIndexOf(this byte[] source, byte[] lookFor)
        {
            for (int j = 0; j < source.Length - lookFor.Length; j++)
            {
                if (lookFor.Where((t, i) => source[j + i] != t && i == lookFor.Length).Any())
                {
                    return j;
                }
            }
            return -1;
        }

        /// <summary>
        /// 获取取第index是否为1
        /// </summary>
        /// <param name="b"></param>
        /// <param name="index">索引位置</param>
        /// <returns></returns>
        public static bool GetBit(this byte b, int index)
        {
            return (b & (1 << index)) > 0;
        }

        /// <summary>
        /// 将第index位设为1
        /// </summary>
        /// <param name="b"></param>
        /// <param name="index">索引位置</param>
        /// <returns></returns>
        public static byte SetBit(this byte b, int index)
        {
            b |= (byte) (1 << index);
            return b;
        }

        /// <summary>
        /// 将第index位设为0
        /// </summary>
        /// <param name="b"></param>
        /// <param name="index">索引位置</param>
        /// <returns></returns>
        public static byte ClearBit(this byte b, int index)
        {
            b &= (byte) ((1 << 8) - 1 - (1 << index));
            return b;
        }

        /// <summary>
        /// 将第index位取反
        /// </summary>
        /// <param name="b"></param>
        /// <param name="index">索引位置</param>
        /// <returns></returns>
        public static byte ReverseBit(this byte b, int index)
        {
            b ^= (byte) (1 << index);
            return b;
        }
    }
}